package tool

import (
	"bytes"
	"context"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"github.com/bytectlgo/edge-tts/pkg/edge_tts"
	"github.com/gopxl/beep/v2"
	"github.com/gopxl/beep/v2/mp3"
	"github.com/gopxl/beep/v2/speaker"
	"io"
	"log"
	"os"
	"strings"
	"sync"
	"time"
)

var initSpeaker sync.Once
var ctrl beep.Ctrl
var initFlag bool

// 计算md5值
func md5Encode(name string) string {
	hash := md5.New()
	_, err := hash.Write([]byte(name))
	if err != nil {
		log.Println("md5计算失败")
	}
	return hex.EncodeToString(hash.Sum(nil))
}

func PlayAudio(text string) {
	if strings.TrimSpace(text) == "" {
		return
	}
	fileName := md5Encode(text) + ".mp3"
	//清除正在播放的内容
	if initFlag {
		speaker.Clear()
	}
	var err error
	//判断临时目录是否存在
	_, err = os.Stat("./tmp")
	if err != nil {
		os.Mkdir("./tmp", 0750)
	}

	//判断临时目录下是否存在当前翻译的临时文件
	_, err = os.Stat("./tmp/" + fileName)
	var data []byte
	if err != nil {
		//不存在则发起网络请求下载
		// 创建新的 TTS 客户端，设置文本和语音
		comm := edge_tts.NewCommunicate(
			text,
			"zh-CN-XiaoxiaoNeural",
			edge_tts.WithRate("+0%"),
			edge_tts.WithVolume("+0%"),
			edge_tts.WithPitch("+0Hz"),
		)

		// 创建带超时的上下文
		ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
		defer cancel()
		// 生成音频文件
		err = comm.Save(ctx, fmt.Sprintf("./tmp/%s", fileName), "")
		if err != nil {
			log.Println("生成音频失败！")
			return
		}
	}
	//存在则读取文件数据
	file, _ := os.Open("./tmp/" + fileName)
	data, _ = io.ReadAll(file)
	if len(data) == 0 {
		file.Close()
		os.Remove("./tmp/" + fileName)
		return
	}
	//解码
	streamers, format, err := mp3.Decode(io.NopCloser(bytes.NewReader(data)))
	if err != nil {
		log.Println("解码失败")
	}
	//时长
	second := (float64(len(data)) / float64(format.SampleRate)) + 1

	//初始化播放
	initSpeaker.Do(func() {
		err = speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
		if err != nil {
			log.Println("初始化失败播放器：", err.Error())
		}
		initFlag = true
	})
	ctrl = beep.Ctrl{Streamer: streamers}
	if err != nil {
		log.Println("初始化失败", err.Error())
	}
	speaker.Play(&ctrl)

	log.Println("语音时长", second)
	log.Println(len(data), format.SampleRate)
	timer := time.NewTimer(time.Second * time.Duration(second))
	select {
	case <-timer.C:
	}
	log.Println("执行完毕")
}
